package simulation;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import util.Location;
import util.Pixmap;
import util.Sprite;
import util.Vector;


/**
 * defines a Mass.
 *
 * @author Robert C. Duvall
 * edited by Schwartz & Roy
 */
public class Mass extends Sprite {
    // reasonable default values
    public static final Dimension DEFAULT_SIZE = new Dimension(16, 16);
    public static final Pixmap DEFAULT_IMAGE = new Pixmap("mass.gif");
    // properties of each mass
    private double myMass;
    private Vector myAcceleration;

    /**
     * constructor for Mass.
     * @param x is the x-coordinate
     * @param y is the y-coordinate
     * @param mass is the mass value
     */
    public Mass(double x, double y, double mass) {
        super(DEFAULT_IMAGE, new Location(x, y), DEFAULT_SIZE);
        myMass = mass;
        myAcceleration = new Vector();
    }

    /**
     * applies forces to Mass and updates velocity vector.
     * @param elapsedTime is elapsed time
     * @param bounds of simulation
     */
    @Override
    public void update(double elapsedTime, Dimension bounds) {
        getBounce(bounds);
        super.update(elapsedTime, bounds);
    }

    /**
     * Paints the mass, currently using a colored oval.
     * @param pen
     */
    @Override
    public void paint(Graphics2D pen) {
        pen.setColor(Color.BLACK);
        pen.fillOval((int) getLeft(), (int) getTop(),
                (int) getWidth(), (int) getHeight());
    }

    /**
     * Use the given force to change this mass's acceleration.
     * @param force is the force to add
     */
    public void applyForce(Vector force) {
        myAcceleration.sum(force);
    }

    /**
     * Convenience method.
     * @param other is the other Mass
     * @return the distance between this Mass and other
     */
    public double distance(Mass other) {
        // this is a little awkward, so hide it
        return new Location(getX(),
                getY()).distance(new Location(other.getX(), other.getY()));
    }

    /**
     * check for move out of bounds.
     * @param bounds of simulation
     * @return force vector of bounce
     */
    private Vector getBounce(Dimension bounds) {
        getVelocity().sum(myAcceleration);
        myAcceleration.reset();
        final double IMPULSE_MAGNITUDE = -2;
        Vector impulse = new Vector();
        if (getLeft() < 0) {
            setCenter(getWidth() / 2, getY());
            impulse = new Vector(RIGHT_DIRECTION, IMPULSE_MAGNITUDE);
        }
        else if (getRight() > bounds.width) {
            setCenter(bounds.width - getWidth() / 2, getY());
            impulse = new Vector(LEFT_DIRECTION, IMPULSE_MAGNITUDE);
        }
        if (getTop() < 0) {
            setCenter(getX(), getHeight() / 2);
            impulse = new Vector(DOWN_DIRECTION, IMPULSE_MAGNITUDE);
        }
        else if (getBottom() > bounds.height) {
            setCenter(getX(), bounds.height - getHeight() / 2);
            impulse = new Vector(UP_DIRECTION, IMPULSE_MAGNITUDE);
        }
        impulse.scale(getVelocity().getRelativeMagnitude(impulse));
        applyForce(impulse);
        getVelocity().sum(myAcceleration);
        myAcceleration.reset();
        return impulse;
    }

    /**
     * @return the mass of Mass object.
     */
    public double getMass() {
        return myMass;
    }

    /**
     * @return the acceleration of Mass object.
     */
    public Vector getAcceleration() {
        return myAcceleration;
    }
}
